
/* Copyright (c) Mark J. Kilgard, 1994. */

/* This program is freely distributable without licensing fees
   and is provided without guarantee or warrantee expressed or
   implied. This program is -not- in the public domain. */

/* Don't take this program too seriously.  It is just a hack. */

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <GL/glut.h>

GLfloat light_diffuse[] =
{1.0, 0.0, 0.0, 1.0};
GLfloat light_position[] =
{1.0, 1.0, 1.0, 0.0};
GLUquadricObj *qobj;

int win1, win2, submenu1, submenu2;

int list = 1;

float thetime = 0.0;

void
display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	if (glutGetWindow() == win1) {
		glCallList(list);   /* render sphere display list */
	} else {
		glCallList(1);      /* render sphere display list */
	}
	glutSwapBuffers();
}

void
display_win1(void)
{
	glPushMatrix();
	glTranslatef(0.0, 0.0, -1 - 2 * sin(thetime));
	display();
	glPopMatrix();
}

void
idle(void)
{
	GLfloat light_position[] =
	{1.0, 1.0, 1.0, 0.0};

	glutSetWindow(win1);
	thetime += 0.05;
	light_position[1] = 1 + sin(thetime);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	display_win1();
}

/* ARGSUSED */
void
delayed_stop(int value)
{
	glutIdleFunc(NULL);
}

void
it(int value)
{
	glutDestroyWindow(glutGetWindow());
	printf("menu selection: win=%d, menu=%d\n", glutGetWindow(), glutGetMenu());
	switch (value) {
	case 1:
		if (list == 1) {
			list = 2;
		} else {
			list = 1;
		}
		break;
	case 2:
		exit(0);
		break;
	case 3:
		glutAddMenuEntry("new entry", value + 9);
		break;
	case 4:
		glutChangeToMenuEntry(1, "toggle it for drawing", 1);
		glutChangeToMenuEntry(3, "motion done", 3);
		glutIdleFunc(idle);
		break;
	case 5:
		glutIdleFunc(NULL);
		break;
	case 6:
		glutTimerFunc(2000, delayed_stop, 0);
		break;
	default:
		printf("value = %d\n", value);
	}
}

void
init(void)
{
	gluQuadricDrawStyle(qobj, GLU_FILL);
	glNewList(1, GL_COMPILE);  /* create sphere display list */
	gluSphere(qobj, /* radius */ 1.0, /* slices */ 20,  /* stacks

                                                       */ 20);
	glEndList();
	gluQuadricDrawStyle(qobj, GLU_LINE);
	glNewList(2, GL_COMPILE);  /* create sphere display list */
	gluSphere(qobj, /* radius */ 1.0, /* slices */ 20,  /* stacks

                                                       */ 20);
	glEndList();
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	gluPerspective( /* field of view in degree */ 40.0,
	        /* aspect ratio */ 1.0,
	        /* Z near */ 1.0, /* Z far */ 10.0);
	glMatrixMode(GL_MODELVIEW);
	gluLookAt(0.0, 0.0, 5.0,  /* eye is at (0,0,5) */
	          0.0, 0.0, 0.0,      /* center is at (0,0,0) */
	          0.0, 1.0, 0.);      /* up is in positive Y direction */
	glTranslatef(0.0, 0.0, -1.0);
}

void
menustate(int inuse)
{
	printf("menu is %s\n", inuse ? "INUSE" : "not in use");
	if (!inuse) {
	}
}

void
keyboard(unsigned char key, int x, int y)
{
	if (isprint(key)) {
		printf("key: `%c' %d,%d\n", key, x, y);
	} else {
		printf("key: 0x%x %d,%d\n", key, x, y);
	}
}

void
special(int key, int x, int y)
{
	char *name;

	switch (key) {
	case GLUT_KEY_F1:
		name = "F1";
		break;
	case GLUT_KEY_F2:
		name = "F2";
		break;
	case GLUT_KEY_F3:
		name = "F3";
		break;
	case GLUT_KEY_F4:
		name = "F4";
		break;
	case GLUT_KEY_F5:
		name = "F5";
		break;
	case GLUT_KEY_F6:
		name = "F6";
		break;
	case GLUT_KEY_F7:
		name = "F7";
		break;
	case GLUT_KEY_F8:
		name = "F8";
		break;
	case GLUT_KEY_F9:
		name = "F9";
		break;
	case GLUT_KEY_F10:
		name = "F11";
		break;
	case GLUT_KEY_F11:
		name = "F12";
		break;
	case GLUT_KEY_LEFT:
		name = "Left";
		break;
	case GLUT_KEY_UP:
		name = "Up";
		break;
	case GLUT_KEY_RIGHT:
		name = "Right";
		break;
	case GLUT_KEY_DOWN:
		name = "Down";
		break;
	case GLUT_KEY_PAGE_UP:
		name = "Page up";
		break;
	case GLUT_KEY_PAGE_DOWN:
		name = "Page down";
		break;
	case GLUT_KEY_HOME:
		name = "Home";
		break;
	case GLUT_KEY_END:
		name = "End";
		break;
	case GLUT_KEY_INSERT:
		name = "Insert";
		break;
	default:
		name = "UNKONW";
		break;
	}
	printf("special: %s %d,%d\n", name, x, y);
}

void
mouse(int button, int state, int x, int y)
{
	printf("button: %d %s %d,%d\n", button, state == GLUT_UP ? "UP" : "down", x, y);
}

void
motion(int x, int y)
{
	printf("motion: %d,%d\n", x, y);
}

void
visible(int status)
{
	printf("visible: %s\n", status == GLUT_VISIBLE ? "YES" : "no");
}

void
enter_leave(int state)
{
	printf("enter/leave %d = %s\n",
	       glutGetWindow(),
	       state == GLUT_LEFT ? "left" : "entered");
}

int
main(int argc, char **argv)
{
	qobj = gluNewQuadric();
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	win1 = glutCreateWindow("sphere");
	glutEntryFunc(enter_leave);
	init();
	glutDisplayFunc(display_win1);
	glutCreateMenu(it);
	glutAddMenuEntry("toggle draw mode", 1);
	glutAddMenuEntry("exit", 2);
	glutAddMenuEntry("new menu entry", 3);
	glutAddMenuEntry("motion", 4);
	glutAttachMenu(GLUT_LEFT_BUTTON);
	glutCreateMenu(it);
	glutAddMenuEntry("yes", 1);
	glutAddMenuEntry("no", 2);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	win2 = glutCreateWindow("second window");
	glutEntryFunc(enter_leave);
	glutKeyboardFunc(keyboard);
	glutSpecialFunc(special);
	glutMouseFunc(mouse);
#if 0
	glutMotionFunc(motion);
#endif
	glutVisibilityFunc(visible);
	init();
	light_diffuse[1] = 1;
	light_diffuse[2] = 1;
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glutDisplayFunc(display);
	submenu1 = glutCreateMenu(it);
	glutAddMenuEntry("submenu a", 666);
	glutAddMenuEntry("submenu b", 777);
	submenu2 = glutCreateMenu(it);
	glutAddMenuEntry("submenu 1", 25);
	glutAddMenuEntry("submenu 2", 26);
	glutAddSubMenu("submenuXXX", submenu1);
	glutCreateMenu(it);
	glutAddSubMenu("submenu", submenu2);
	glutAddMenuEntry("stop motion", 5);
	glutAddMenuEntry("delayed stop motion", 6);
	glutAddSubMenu("submenu", submenu2);
	glutAttachMenu(GLUT_LEFT_BUTTON);
	glutMenuStateFunc(menustate);
	glutMainLoop();
	return 0;             /* ANSI C requires main to return int. */
}
